﻿using System;
using System.IO;

namespace GameBasic.IO
{
    public struct FileOperation
    {
        public delegate void Callback(ref FileOperation op, TaskEvent e);

        public enum Type
        {
            Read,
            Write,
            Delete
        }

        public Type type;
        public string path;
        public string data;
        public bool appendWrite;

        // No need?
        public Callback callback;

        public FileOperation Execute()
        {
            callback?.Invoke(ref this, TaskEvent.OnStart);

            Exception e = type switch
            {
                Type.Read => Read(),
                Type.Write => Write(),
                Type.Delete => Delete(),
                _ => null,
            };

            TaskEvent result = TaskEvent.OnComplete;
            if (e != null) 
            {
                if (callback == null)
                {
                    throw (e);
                }
                else
                {
                    data = e.ToString();
                    result = TaskEvent.Error;
                }
            }

            callback?.Invoke(ref this, result);
            return this;
        }

        Exception Read()
        {
            Exception result = null;

            if (!File.Exists(path))
            {
                result = new FileNotFoundException(path);
            }
            else
            {
                StreamReader stream = null;
                try
                {
                    stream = new StreamReader(path);
                    data = stream.ReadToEnd();
                }
                catch (Exception e)
                {
                    result = e;
                }
                finally
                {
                    if (stream != null)
                    {
                        stream.Close();
                        stream.Dispose();
                    }
                }
            }

            return result;
        }

        Exception Write()
        {
            StreamWriter stream = null;
            FileInfo fileinfo = new FileInfo(path);

            Exception result = null;
            try
            {
                // create dir
                DirectoryInfo dir = fileinfo.Directory;
                if (!fileinfo.Directory.Exists)
                    dir.Create();

                stream = new StreamWriter(path, appendWrite);
                stream.Write(data);
            }
            catch (Exception e)
            {
                result = e;
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                    stream.Dispose();
                }
            }

            return result;
        }

        Exception Delete()
        {
            Exception result = null;
            try
            {
                if (File.Exists(path))
                {
                    File.Delete(path);
                }
                else if (Directory.Exists(path))
                {
                    Directory.Delete(path, true);

                    /*
                    DirectoryInfo dir = new DirectoryInfo(Path.GetDirectoryName(path));
                    //返回目录中所有文件和子目录
                    FileSystemInfo[] fileinfo = dir.GetFileSystemInfos();
                    foreach (FileSystemInfo i in fileinfo)
                    {
                        //判断是否文件夹
                        if (i is DirectoryInfo)
                        {
                            DirectoryInfo subdir = new DirectoryInfo(i.FullName);
                            //删除子目录和文件
                            subdir.Delete(true);
                        }
                        else
                        {
                            //删除指定文件
                            File.Delete(i.FullName);
                        }
                    }
                    */
                }

            }
            catch (Exception e)
            {
                result = e;
            }

            return result;
        }

        public static FileOperation Read(string path, Callback callback = null)
        {
            return new FileOperation()
            {
                type = Type.Read,
                path = path,
                callback = callback
            };
        }

        public static FileOperation Write(string path, string data, bool append = false, Callback callback = null)
        {
            return new FileOperation()
            {
                type = Type.Write,
                path = path,
                data = data,
                appendWrite = append,
                callback = callback
            };
        }

        public static FileOperation Delete(string path, Callback callback = null)
        {
            return new FileOperation()
            {
                type = Type.Delete,
                path = path,
                callback = callback
            };
        }
    }
}